Outlook Needs Better Rules

Mr. Muskrat on 2008-03-20T15:03:08

At $work we use Outlook with an Exchange server for our email. Recently I've taken on system administration tasks for my group. Any email sent to root on our servers goes to me.

One of the servers is running OpenNMS (apparently it's not configured correctly). OpenNMS keeps sending email to me with subjects like 'Notice #XXXX: node some.node.domain.local down' and 'RESOLVED: Notice #XXXX: node some.node.domain.local down'. Some days I get 15 or 20 notices (plus the corresponding resolved notices). Other days I get 50 - 75 notices (plus the resolved). (More often than not, the downtime is super short and I get two notices and two resolves for the same system in one minute).

Until I can finish configuring OpenNMS (so that it's not so darn sensitive) I'd like to set up Outlook to automatically mark the notice and corresponding resolve as read. Outlook's rules don't allow for wildcards or capturing or anything that resembles a 21st century feature. I've done some Excel macros in the past but I've never needed to muck with VBA in Outlook so I really don't know where to start (other than what I've found doing a Google for it). I also downloaded a few sample scripts for doing Outlook inbox/message manipulation in Perl.

Are there any Outlook gurus reading this? Do you have any suggestions?


Maybe I'm Spoiled

Mr. Muskrat on 2008-03-20T15:26:34

Maybe I'm expecting too much from software that has been around as long as Outlook. Maybe I'm spoiled after using Linux for as long as I have (I've been using it since about 1998 even though I maintained a Windows system for gaming until recent). Things that I take for granted on a Linux system just don't work that way on Windows. Apparently email is one of those things.

Re:Maybe I'm Spoiled

barbie on 2008-03-20T18:05:29

Take a look at my Mail-Outlook distribution. Although it's not a solution for your immediate problem, it might give you a start for writing something of your own. Personally I would write a rule in Outlook to refile the incoming messages into a dedicated email folder and then have a script poll that folder every $interval minutes. You can set mail items as read/unread through the API. That's how I used to run the CPAN Testing on my Windows box :)

Re:Maybe I'm Spoiled

Mr. Muskrat on 2008-03-20T19:05:54

Those messages are already going to a personal folder.

I ran across Mail::Outlook in my searches and made a note to check it out. Now that you have said that I might want to look at how you did it, I'll put it at the top of my list of things to check out.

Thanks Barbie!

UnRead isn't read/write?

Mr. Muskrat on 2008-03-24T16:53:22

Any idea on how to mark items as read from Perl? I'm attempting to use the (supposedly) read/write boolean property UnRead but it's giving me "Can't modify non-lvalue subroutine call at outlook.pl line 69."

#!/usr/bin/perl
# This started as Shawn A. Clifford's Win32_Outlook_Folders.pl
use strict;
use Win32::OLE qw( in valof with );
use Win32::OLE::Variant;
use Win32::OLE::Const 'Microsoft Outlook';
$| = 1;

my $Outlook; # An instance of Outlook
#  Use existing instance if Outlook is already running
eval { $Outlook = Win32::OLE->GetActiveObject('Outlook.Application') };
die "Outlook is not installed" if $@;
unless ( defined $Outlook )
{
   $Outlook = Win32::OLE->new('Outlook.Application', sub { $_[0]->Quit; })
      or die "Oops, cannot start Outlook";
}

my $ol = Win32::OLE::Const->Load($Outlook);
my $namespace = $Outlook->GetNamespace("MAPI");
my %Folders;            # Hash table of folder names -> EntryID
for my $index ( 1 .. $namespace->Folders->Count ) {
   my $folder = $namespace->Folders($index)->Name;
   my $oFolder = $namespace->Folders($index);
   if ( $folder eq 'Personal Folders' )
   {
      #  Save the folder<->EntryID pair
      $Folders{ $folder } = $namespace->Folders->Item($index)->EntryID;
      GetEntryIDs( $oFolder, 1 );
   }
}

my $oFolder = $namespace->GetFolderFromID($Folders{'OpenNMS'});

my %Items;
my $oItems = $oFolder->Items;
if ( $oItems->Count == 0 )
{
   print "No messages found\n";
   exit;
}
else
{
   for my $oItem ( in $oItems )
   {
      next if ! $oItem->UnRead;
      my $Subject = $oItem->Subject;
      if ( $Subject =~ /Notice #(\d+):/ )
      {
         my $notice = $1;
         my $resolved = 0;
         if ( $Subject =~ /^RESOLVED:/ )
         {
            $resolved = 1;
         }
         $Items{ $notice }{ $resolved } = $oItem;
      }

   }
}

my @Items = sort keys %Items;

for my $notice ( @Items )
{
   my $count = keys %{ $Items{ $notice } };
   if ( $count == 2 )
   {
      $Items{ $notice }{0}->UnRead = 0; # line 69
      $Items{ $notice }{1}->UnRead = 0;
      print "$notice => Marked as read\n";
   }
}

sub GetEntryIDs {
   my ( $Top, $depth ) = @_;
   die "insufficient args: GetEntryIDs()\n" if ( ! $depth );

   #  Collection indexes start at 1, not 0
   for my $index ( 1 .. $Top->Folders->Count )
   {
      my $folder = $Top->Folders->Item($index)->Name;
      $Folders{ $folder } = $Top->Folders->Item($index)->EntryID;

      if ( $Top->Folders->Item($index)->Folders->Count > 1 )
      {
         GetEntryIDs( $Top->Folders->Item($index), $depth + 1 );
      }
   }
}

Re:UnRead isn't read/write?

barbie on 2008-03-25T11:49:43

Not tried, but you might find this a bit of a d'oh! moment :)

$Items{ $notice }{0}->{UnRead} = 0; # line 69
$Items{ $notice }{1}->{UnRead} = 0;

Your original call was referencing a subroutine and you can't pass arguments to subroutines like that in most languages ;) However, as this is a property you should reference it as you would a hash key/value. The internal OLE workings do the transformations, and will generate read-only accessors for some of the properties, hence the error you got. I had a similar problem with 'From'.

Re:UnRead isn't read/write?

Mr. Muskrat on 2008-03-25T14:22:22

That was the problem and as soon as I saw it, I knew that it would work. Very much a d'oh moment! Thanks Barbie.